#include "common/pch.h"

#include <format>

#include <cftc/reflect/class.h>
#include <cftc/reflect/field.h>
#include <cftf/loger/syslog.h>

#include "object/transport.h"
#include "object/unit.h"
#include "metadata/creature_model_info.h"

namespace battle::object
{

	Unit::Unit():i_motionMaster(this)
	{

	}

	void Unit::SetCharm(Unit* pet)
	{
		SetCharmGuid(pet ? pet->GetObjectGuid() : ObjectGuid());
	}

    void Unit::SetDisplayId(unsigned int modelId)
    {
        SetUint32Value(UNIT_FIELD_DISPLAYID, modelId);

        UpdateModelData();

#if 0
        if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet())
        {
            Pet* pet = ((Pet*)this);
            if (!pet->isControlled())
            {
                return;
            }
            Unit* owner = GetOwner();
            if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
            {
                ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID);
            }
        }
#endif
    }

    void Unit::UpdateModelData()
    {
        if (auto const* modelInfo = mt::CreatureModelInfo::GetElement(GetDisplayId()))
        {
            // we expect values in database to be relative to scale = 1.0
            SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, GetObjectScale() * modelInfo->bounding_radius);

            // never actually update combat_reach for player, it's always the same. Below player case is for initialization
            if (GetTypeId() == TYPEID_PLAYER)
            {
                SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
            }
            else
            {
                SetFloatValue(UNIT_FIELD_COMBATREACH, GetObjectScale() * modelInfo->combat_reach);
            }
        }
    }

    unsigned int Unit::GetCreatePowers(Powers power) const
    {
#if 0
        switch (power)
        {
        case POWER_HEALTH:      return 0;                   // is it really should be here?
        case POWER_MANA:        return GetCreateMana();
        case POWER_RAGE:        return POWER_RAGE_DEFAULT;
        case POWER_FOCUS:       return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : POWER_FOCUS_DEFAULT);
        case POWER_ENERGY:      return POWER_ENERGY_DEFAULT;
        case POWER_HAPPINESS:   return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : POWER_HAPPINESS_DEFAULT);
        default: break; //MAX_POWERS and POWERS_ALL probably should not belong to the enum Powers to do not require the default: case
        }
#endif
        return 0;
    }

    void Unit::SetPowerType(Powers new_powertype)
    {
#if 0
        // set power type
        SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype);

        // group updates
        if (GetTypeId() == TYPEID_PLAYER)
        {
            if (((Player*)this)->GetGroup())
            {
                ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
            }
        }
        else if (((Creature*)this)->IsPet())
        {
            Pet* pet = ((Pet*)this);
            if (pet->isControlled())
            {
                Unit* owner = GetOwner();
                if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
                {
                    ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
                }
            }
        }

        // special cases for power type switching (druid and pets only)
        if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->IsPet()))
        {
            uint32 maxValue = GetCreatePowers(new_powertype);
            uint32 curValue = maxValue;

            // special cases with current power = 0
            if (new_powertype == POWER_RAGE)
            {
                curValue = 0;
            }

            // set power (except for mana)
            if (new_powertype != POWER_MANA)
            {
                SetMaxPower(new_powertype, maxValue);
                SetPower(new_powertype, curValue);
            }
        }
#endif
    }

    float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
    {
        if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
        {
            cftf::loger::SysLog::Instance().Error("attempt to access nonexistent modifier value from UnitMods!");
            return 0.0f;
        }

        if (modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
        {
            return 0.0f;
        }

        return m_auraModifiersGroup[unitMod][modifierType];
    }


}